iT邦幫忙

2022 iThome 鐵人賽

DAY 18
2

今天的內容是來發一些刷題的時候常用的C++ code templates
致敬一下PoJen學長的Leetcode刷題pattern系列文章

不過學長的文章比較focus on pattern
也就是每個topic(像官神的github題目分類整理)都會有一些大致上的思路

但筆者今天這篇文章主要是focus on code templates
比較像是官神的github template整理

分成三部分


一些簡單常用的function

(應該要知道或是背起來)

累加
(對c++就是要打這麼長才能做到python sum做到的事情)

int sum = accumulate(v.begin(),v.end(),0);

取最值

int maxVal = *max_element(v.begin(),v.end());

轉換

string str = to_string(some_int);
int i = atoi(some_string);
float f = atof(some_other_string);

vector to set

set<int> s( vec.begin(), vec.end() );

set to vector

vector<int> newVec;
newVec.assign( s.begin(), s.end() );

(這兩個一起用拿來去重還蠻方便的)

custom compare
-> priority_queue:

auto comp = [](const SomeType& a, const SomeType& b) { return a.second > b.second; };
priority_queue< SomeType , vector<SomeType>, decltype(comp) > pq(comp)

->map:

auto comp = [](const SomeType& a, SomeType string& b) { return a.length() < b.length(); };
map<SomeType, SomeType, decltype(comp)> myMap(comp);

接下來是

稍微有點長的Data Structure

在刷題刷到很熟練的時候常常會懶得打那麼多字
直接開自己的Google Keep把這些code貼上或是改一改來用

但雖然這樣偷懶的做法在比賽或是刷題的時候可以省一點點時間
但需要的時候筆者是可以直接一字不差的打出這些code的
千萬不要在還沒有刷題刷到熟練的時候就每次偷懶貼過去用
而且一要好好熟練跟理解這些template在做什麼
以免在面試的時候把最基本的一些東東打一打被面試官看到bug因此扣分

DSU

class DSU {
  public:
    DSU(int numOfNodes) {
        n = numOfNodes;
        par.resize(n);
        iota(par.begin(), par.end(), 0); //assign 0 to n-1 to vector par
    }
    int find(int a){
        if(par[a] == a) return a;
        par[a] = find(par[a]); //path reduction
        return par[a];
    }
    void join(int a, int b){
        int pa = find(a);
        int pb = find(b);
        if(pa == pb) return;
        par[pa] = par[pb] = min(pa,pb); //always choose min as parent
    }
    vector<int> par; //vector of parents
    int n;
};

//usage:
DSU dsu(numOfNodes);
int parA = dsu.find(a);
dsu.join(a,b);

Trie
(LC 208的解答)
提到Trie就想要再提到一次不錯的變化題LC 677:https://leetcode.com/problems/map-sum-pairs/

class Trie {
  public:
    class TrieNode {
      public:
        array<TrieNode*,26> child;
        bool isEnd;
    };
    
    Trie() {
        root = new TrieNode();
    }
    
    /** Inserts a word into the trie. */
    void insert(const string& word) {
        TrieNode* cur = root;
        for(char c: word){
            if(cur->child[c-'a'] == nullptr){
                cur->child[c-'a'] = new TrieNode();
            }
            cur = cur->child[c-'a'];
        }
        cur->isEnd = true;
    }
    
    /** Returns true if the word is in the trie. */
    bool search(const string& word) {
        TrieNode* cur = root;
        for(char c: word){
            if(cur->child[c-'a'] == nullptr){
                return false;
            }
            cur = cur->child[c-'a'];
        }
        return cur->isEnd;
    }
    
    /** Returns true if there is any word in the trie that starts with the given prefix. */
    bool startsWith(const string& prefix) {
        TrieNode* cur = root;
        for(char c: prefix){
            if(cur->child[c-'a'] == nullptr){
                return false;
            }
            cur = cur->child[c-'a'];
        }
        return true;
    }
    TrieNode* root;
};

//usage: 
Trie t;
for(auto& w : words) t.insert(w);

BIT

class BIT {
    public:
    BIT(int n){
        bit.resize(n+1); // bit is always 1-index.
    }
    int query(int idx){ // input parameter is 0-index for convenience
        idx++;
        int ans = 0;
        while(idx){
            ans += bit[idx];
            idx -= idx & -idx;
        }
        return ans;
    }
    int query(int L, int R){ // [L,R], both ends are included
        return query(R) - query(L-1);
    }

    void update(int idx, int val){ // input parameter is 0-index for convenience
        int n = bit.size()-1;
        idx++;
        while(idx <= n){
            bit[idx] += val;
            idx += idx & -idx;
        }
    }
    vector<int> bit;
};

//usage:
BIT bit(maxVal);
bit.update(idx /*use 0-index here*/, val);
bit.query(L,R);

Segment Tree
(說實話筆者覺得好像沒有哪一題是非得要用Segment Tree才能做的
雖然競賽的時候各式各樣的線段樹是基本常識,
個人認為對刷題和面試而言背熟線段樹的Template CP值不是很高)
需要的話請參考官神的線段樹template
https://github.com/wisdompeak/LeetCode/blob/master/Template/SegmentTree/range_sum.cpp

For 4-dir maze related problem
太多graph的題目會用到這個4-direction的for loop了特別提一下...

vector<pair<int,int>> dir{{1,0}, {-1,0}, {0,1}, {0,-1}};
for(auto& d: dir){
    int nx = x + d.first;
    int ny = y + d.second;
    if(nx>=0 && ny>=0 && nx<m && ny<n /*通常還有 visit[nx][ny] == false*/){
    }
}

在字串題,c++輸python輸最大的
(除了[a:b]的subscrpition)
就是沒有一個好用的split(delimiter) function了
好在有人幫各位打好這個function了
https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string

vector<string> split (string& s, string& d) {
   size_t pos_start = 0, pos_end, l = d.length();
   string token;
   vector<string> res;
   
   while ((pos_end = s.find (delimiter, pos_start)) != string::npos) {
       token = s.substr (pos_start, pos_end - pos_start);
       pos_start = pos_end + l;
       res.push_back(token);
   }

   res.push_back(s.substr (pos_start));
   return res;
}

接下來就是

各個topic的template

以面試會考的難度而言
比較套路一點的像是
Sliding Window/backtrack/Kadane/monotonic stack/topological sort/dijkstra/bfs等等等等
雖然好像都可以尻模板去改
但是就沒有向上面那些資料結構的重複性那麼高,

而且要打的code也沒那麼長,打完改完幾乎就是題目的解答
(就算是很套路的題目,也應該要可以自己把整個演算法的大框架現場寫出來)
基本上不應該需要整理模板尻上來改
筆者就不附錄其他的整理,只放最基本最簡單的binary search模板
(因為labuladong放的模板超難用,害我當初搞混很久Orz)

Binary Search for
LC 34. Find First and Last Position of Element in Sorted Array
(套用官神模板)

int n = nums.size();

//找左界
int L = 0, R = n-1;
while(L<R){
    int mid = L + (R-L)/2;
    if(nums[mid] >= target){
        R = mid;
    }else{
        L = mid+1;
    }
}
//跳出迴圈的時候 L==R, nums[L] != target就是沒找到

//找右界
L = 0; R = n-1;
while(L<R){
    int mid = R - (R-L)/2;
    if(nums[mid] <= target){
        L = mid;
    }else{
        R = mid-1;
    }
}
//跳出迴圈的時候 L==R, nums[L] != target就是沒找到

Sliding Window可以參考
https://leetcode.com/problems/frequency-of-the-most-frequent-element/discuss/1175088/C++-Maximum-Sliding-Window-Cheatsheet-Template!


上一篇
如何保持刷題動力
下一篇
推薦的hard題目
系列文
0到100的軟體工程師面試之路31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

我要留言

立即登入留言